package com.yjzx.binlog.config;

import com.yjzx.util.binlog.core.config.BinLogBean;
import com.yjzx.util.binlog.core.entiry.recordIndex.BinaryLogClientIndex;
import com.yjzx.util.binlog.core.entiry.recordIndex.FileRecordBinLogIndex;
import com.yjzx.util.binlog.core.entiry.recordIndex.MemoryRecordBinLogIndex;
import com.yjzx.util.binlog.core.entiry.Conf;
import com.yjzx.util.binlog.core.executor.BinLogExecutor;
import com.yjzx.util.binlog.core.handle.BinlogHandle;
import com.yjzx.util.binlog.core.listener.MysqlBinLogListener;
import com.yjzx.util.binlog.core.util.BinLogUtils;
import com.yjzx.util.binlog.core.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

/**
 * @author yjzx
 * @date 2024/9/20
 * @description BinlogConfig
 */
@Slf4j
public class BinlogConfig {
    private final static BinlogConfig INSTANCE = new BinlogConfig();
    private final BinLogBean binLogBean;
    private final MysqlBinLogListener mysqlBinLogListener;

    public static BinlogConfig getInstance() {
        return INSTANCE;
    }

    /**
     * 初始化binlog监听器处理器
     * @param listeners 监听器
     * @return
     */
    public BinlogHandle initExecutor(List<BinLogExecutor> listeners) {
        return new BinlogHandle(binLogBean, mysqlBinLogListener, listeners);
    }

    /**
     * 加载binLog配置
     */
    private BinlogConfig() {
        Properties properties = loadProperties("BinlogListener.properties");
        binLogBean = new BinLogBean();
        String threadSize = properties.getProperty("binlog.properties.consumerThreads");
        binLogBean.setConsumerThreads(StringUtils.isNotBlank(threadSize) ? 5 : Integer.parseInt(threadSize));
        Conf conf = new Conf();
        conf.setClassname(properties.getProperty("binlog.properties.datasource.classname"));
        conf.setHost(properties.getProperty("binlog.properties.datasource.host"));
        conf.setPort(Integer.parseInt(properties.getProperty("binlog.properties.datasource.port")));
        conf.setUsername(properties.getProperty("binlog.properties.datasource.username"));
        conf.setPassword(properties.getProperty("binlog.properties.datasource.password"));

        binLogBean.setDatasource(conf);
        HashMap<String, String> map = new HashMap<>();
        Set<String> strings = properties.stringPropertyNames();
        String key = "binlog.properties.db-table.";
        for (String string : strings) {
            if (string.startsWith(key)) {
                int i = string.indexOf(key);
                map.put(string.substring(i + key.length()), properties.getProperty(string));
            }
        }
        binLogBean.setDbTable(map);

        BinLogUtils.toFileRecordBinLogIndex(binLogBean, loadMemoryBinLogIndex(properties), loadFileBinLogIndex(properties));

        mysqlBinLogListener = new MysqlBinLogListener(binLogBean);
    }

    private static BinaryLogClientIndex loadFileBinLogIndex(Properties properties) {
        String recordFile = properties.getProperty("binlog.properties.file.recordfile");
        recordFile = StringUtils.isNotBlank(recordFile) ? recordFile : null;
        return new FileRecordBinLogIndex(recordFile);
    }

    private static MemoryRecordBinLogIndex loadMemoryBinLogIndex(Properties properties) {
        String binFile = properties.getProperty("binlog.properties.memory.binfile");
        String position = properties.getProperty("binlog.properties.memory.position");
        binFile = StringUtils.isNotBlank(binFile) ? binFile : null;
        long positionL = StringUtils.isNotBlank(position) ?
                Long.parseLong(position) > 0 ? Long.parseLong(position) : -1 : -1;
        return new MemoryRecordBinLogIndex(binFile, positionL);
    }


    /**
     * 加载配置文件
     * @param propertyFileName 配置文件名
     * @return
     */
    public static Properties loadProperties(String propertyFileName) {
        InputStreamReader in = null;
        try {
            ClassLoader loder = Thread.currentThread().getContextClassLoader();

            in = new InputStreamReader(Objects.requireNonNull(loder.getResourceAsStream(propertyFileName)), "UTF-8");
            ;
            Properties prop = new Properties();
            prop.load(in);
            return prop;
        } catch (IOException e) {
            log.error("load {} error!", propertyFileName);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error("close {} error!", propertyFileName);
                }
            }
        }
        throw new RuntimeException("无法获取到配置");
    }
}
